using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace AnimTool
{
    public partial class Form1 : Form
    {

        OpenFileDialog ofd = new OpenFileDialog();

        PreviewForm pf = new PreviewForm();
        public Form1()
        {
            InitializeComponent();

            TreeNode n = new TreeNode();
            n.Name = "Resources";
            n.Text = "Resources";
            n.Tag = "Resources";

            treeView.Nodes.Add(n);            

            n = new TreeNode();
            n.Name = "Animations";
            n.Text = "Animations";
            n.Tag = "Animations";

            treeView.Nodes.Add(n);

            ofd.Title = "Add Image File";
            ofd.InitialDirectory = "c:\\";
            ofd.Filter = "PNG files (*.png)|*.png";
            ofd.RestoreDirectory = true;
            ToggleAnimationSection(false);
            ToggleFrameGenSection(false);
            ToggleFrameSection(false);

            GenerateFramesButton.Enabled = false;
        }

        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (treeView.SelectedNode.Name.Equals("Resources"))
            {
                ToggleAnimationSection(false);
                ToggleFrameGenSection(false);
                ToggleFrameSection(false);
                currentSelectedType = SelectionType.Resources;
            }
            if (treeView.SelectedNode.Name.Equals("Animations"))
            {
                ToggleAnimationSection(false);
                ToggleFrameGenSection(false);
                ToggleFrameSection(false);
                currentSelectedType = SelectionType.Animations;
            }
            if (AnimationMap.ContainsKey(treeView.SelectedNode))
            {
                Animation a = AnimationMap[treeView.SelectedNode];
                SetAnimationFieldData(a);
                ToggleAnimationSection(true);
                ToggleFrameGenSection(true);
                currentSelectedType = SelectionType.Animation;
            }
            if (FrameMap.ContainsKey(treeView.SelectedNode))
            {
                Frame f = FrameMap[treeView.SelectedNode];
                SetFrameFieldData(f);
                ToggleFrameSection(true);
                currentSelectedType = SelectionType.Frame;
            }

        }
        public SelectionType currentSelectedType = SelectionType.Null;
        public enum SelectionType
        {
            Null,
            Animation,
            Frame,
            Animations,
            Resources,
            Resource
        }

        Dictionary<TreeNode, Frame> FrameMap = new Dictionary<TreeNode, Frame>();
        Dictionary<Frame, TreeNode> FrameNodes = new Dictionary<Frame, TreeNode>();
        Dictionary<TreeNode, Animation> AnimationMap = new Dictionary<TreeNode, Animation>();
        Dictionary<Animation, TreeNode> AnimationNodes = new Dictionary<Animation, TreeNode>();
        public static Dictionary<string, Image> ImageMap = new Dictionary<string, Image>();
        List<Animation> Animations = new List<Animation>();
        Animation selectedAnimation;
        Frame selectedFrame;

        private void SetAnimationFieldData(Animation a)
        {
            AnimationNameTextBox.Text = a.Name;
            selectedAnimation = a;
        }
        private void SetFrameFieldData(Frame f)
        {
            selectedFrame = f;

            const string message = "L: {0} T: {1} R: {2} B: {3}";
            FrameDetailsLabel.Text = string.Format(message, f.x, f.y, f.x + f.width, f.y + f.height);
            FrameResourceComboBox.SelectedItem = f.resource;
            FrameOffsetXTextBox.Text = f.x.ToString();
            FrameOffsetYTextBox.Text = f.y.ToString();
            FrameDelayTextBox.Text = f.delay.ToString();
        }
        private void ToggleAnimationSection(bool value)
        {
            AnimationNameTextBox.Enabled = value;
        }

        private void ToggleFrameGenSection(bool value)
        {
            FrameGenResourceComboBox.Enabled = value;
            StartXTextBox.Enabled = value;
            StartYTextBox.Enabled = value;
            NumOfFramesTextBox.Enabled = value;
            IconsPerRowTextBox.Enabled = value;
            FPSTextBox.Enabled = value;
            WidthTextBox.Enabled = value;
            HeightTextBox.Enabled = value;
        }
        private void ToggleFrameSection(bool value)
        {
            
            FrameResourceComboBox.Enabled = value;
            FrameOffsetXTextBox.Enabled = value;
            FrameOffsetYTextBox.Enabled = value;
            FrameDelayTextBox.Enabled = value;
        }
        private void addButton_Click(object sender, EventArgs e)
        {
            if (treeView.SelectedNode.Name.Equals("Resources"))
            {
                if (ofd.ShowDialog() == DialogResult.OK)
                {
                    FileInfo fi = new FileInfo(ofd.FileName);

                    string name = fi.Name.Split('.')[0];

                    Image img = Image.FromFile(fi.FullName);
                    ImageMap[name] = img;

                    TreeNode n = new TreeNode();
                    n.Name = "R*"+name;
                    n.Text = name;
                    n.Tag = "R0";

                    TreeNode p = treeView.Nodes.Find("Resources", true)[0];
                    p.Nodes.Add(n);

                    treeView.Nodes[0].ExpandAll();

                    FrameGenResourceComboBox.Items.Add(name);
                    FrameResourceComboBox.Items.Add(name);
                }
            }
            if (treeView.SelectedNode.Name.Equals("Animations"))
            {
                Animation a = new Animation();
                a.Name = "New Animation";

                TreeNode n = new TreeNode();
                n.Name = "A*" + a.Name;
                n.Text = a.Name;
                n.Tag = "A0";
                TreeNode p = treeView.Nodes.Find("Animations", true)[0];
                p.Nodes.Add(n);

                treeView.Nodes[1].ExpandAll();
                treeView.SelectedNode = n;

                selectedAnimation = a;
                currentSelectedType = SelectionType.Animation;

                Animations.Add(a);                
                AnimationMap[n] = a;
                AnimationNodes[a] = n;
                SetAnimationFieldData(a);
                ToggleAnimationSection(true);
                ToggleFrameGenSection(true);

            }

        }

        private void deleteButton_Click(object sender, EventArgs e)
        {
            if (currentSelectedType == SelectionType.Frame)
            {
                DeleteFrame(selectedFrame);
            }
        }
        public class Animation
        {
            public string Name;
            public List<Frame> Frames = new List<Frame>();
        }

        public class Frame
        {
            public string resource;
            public int x, y, width, height, delay;
        }
        private void AnimationNameTextBox_TextChanged(object sender, EventArgs e)
        {
            selectedAnimation.Name = AnimationNameTextBox.Text;
            treeView.SelectedNode.Text = selectedAnimation.Name;
        }

        private void FrameGenTextBox_TextChanged(object sender, EventArgs e)
        {
            TextBox t = sender as TextBox;
            int r;
            if (!int.TryParse(t.Text, out r))
            {
                t.BackColor = Color.Coral;
            }
            else
            {
                t.BackColor = Color.White;
            }
            if (!IsFrameGenValid)
            {
                GenerateFramesButton.Enabled = false;
            }
            else
            {
                GenerateFramesButton.Enabled = true;
            }
        }

        private bool IsFrameGenValid
        {
            get 
            {
                bool result = true;
                int r;
                result &= int.TryParse(StartXTextBox.Text, out r);
                result &= int.TryParse(StartYTextBox.Text, out r);
                result &= int.TryParse(WidthTextBox.Text, out r);
                result &= int.TryParse(HeightTextBox.Text, out r);
                result &= int.TryParse(IconsPerRowTextBox.Text, out r);
                result &= int.TryParse(NumOfFramesTextBox.Text, out r);
                result &= int.TryParse(FPSTextBox.Text, out r);
                return result;
            }
        }
        private void DeleteFrame(Frame f)
        {
            selectedAnimation.Frames.Remove(f);

            TreeNode n = FrameNodes[f];
            TreeNode p = AnimationNodes[selectedAnimation];
            p.Nodes.Remove(n);

            FrameMap.Remove(n);
            FrameNodes.Remove(f);
        }
        private void AddFrame(Frame f, int i)
        {
            selectedAnimation.Frames.Add(f);
            TreeNode n = new TreeNode();
            n.Name = selectedAnimation.Name + i;
            n.Text = "Frame " + i;
            n.Tag = selectedAnimation.Name + i;
            if (currentSelectedType == SelectionType.Animation) {
                treeView.SelectedNode.Nodes.Add(n);
            }
            else if (currentSelectedType == SelectionType.Frame) {
                int selectedFrameIndex = treeView.SelectedNode.Parent.Nodes.IndexOf(treeView.SelectedNode);
                treeView.SelectedNode.Parent.Nodes.Insert(selectedFrameIndex, n);
            }
            FrameMap[n] = f;
            FrameNodes[f] = n;
        }
        private void GenerateFramesButton_Click(object sender, EventArgs e)
        {
            int startOffsetX = int.Parse(StartXTextBox.Text);
            int startOffsetY = int.Parse(StartYTextBox.Text);
            int frameWidth = int.Parse(WidthTextBox.Text);
            int frameHeight = int.Parse(HeightTextBox.Text);
            int iconsPerRow = int.Parse(IconsPerRowTextBox.Text);
            int numOfFrames = int.Parse(NumOfFramesTextBox.Text);
            int fps = int.Parse(FPSTextBox.Text);

            int delay = (int)((1.0 / (double)fps) * 1000.0);

            for (int tileCount = 0, y = startOffsetY; tileCount < numOfFrames; y += frameHeight)
            {
                int tileRowCount = 0;
                for (int x = startOffsetX; tileCount < numOfFrames && tileRowCount < iconsPerRow; x += frameWidth, tileRowCount++, tileCount++)
                {
                    Frame f = new Frame();
                    f.height = frameHeight;
                    f.width = frameWidth;
                    f.x = x;
                    f.y = y;
                    f.delay = delay;
                    f.resource = FrameGenResourceComboBox.SelectedItem as string;
                    AddFrame(f, tileCount);
                }
            }
        }

        private void PreviewButton_Click(object sender, EventArgs e)
        {

            if (currentSelectedType == SelectionType.Animation)
            {
                pf.Animation = AnimationMap[treeView.SelectedNode];
            }
            else if (currentSelectedType == SelectionType.Frame)
            {
                Animation a = new Animation();
                a.Name = "frame";
                a.Frames.Add(FrameMap[treeView.SelectedNode]);
                pf.Animation = a;
            }
            
            pf.Show();
            pf.Play();
        }

        private void StopButton_Click(object sender, EventArgs e)
        {
            pf.Hide();
            pf.Stop();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            pf.Kill();
        }

        private void Save_Click(object sender, EventArgs e)
        {

            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Title = "Save Animation";
            sfd.InitialDirectory = "c:\\";
            sfd.FileName = selectedAnimation.Name + ".anim";
            sfd.Filter = "Animation files (*.anim)|*.anim";
            sfd.RestoreDirectory = true;

            if (sfd.ShowDialog() == DialogResult.OK)
            {
                Animation a = selectedAnimation;
                int width = a.Frames[0].width;
                int height = a.Frames[0].height;

                string imageFileName = sfd.FileName.Split('.')[0] + ".gif";
                Bitmap b = new Bitmap(width * a.Frames.Count, height);
                Graphics g = Graphics.FromImage(b);
                List<Frame> newFrames = new List<Frame>();

                for (int i = 0; i < a.Frames.Count; i++)
                {
                    Frame f = a.Frames[i];
                    Image srcImage = ImageMap[f.resource];

                    Frame newFrame = new Frame();
                    newFrame.resource = a.Name;
                    newFrame.x = i * width;
                    newFrame.y = 0;
                    newFrame.width = width;
                    newFrame.height = height;
                    Rectangle dst = new Rectangle(newFrame.x, newFrame.y, newFrame.width, newFrame.height);
                    Rectangle src = new Rectangle(f.x, f.y, f.width, f.height);
                    g.DrawImage(srcImage, dst, src, GraphicsUnit.Pixel);

                    newFrames.Add(newFrame);
                }

                b.Save(imageFileName);

                FileInfo fi = new FileInfo(sfd.FileName);
                StreamWriter sw = new StreamWriter(fi.OpenWrite());

                sw.WriteLine(a.Name);
                sw.WriteLine(a.Frames.Count);

                foreach (Frame f in newFrames)
                {
                    const string frameMsg = "{0}, {1}, {2}, {3}, {4}, {5}";
                    sw.WriteLine(string.Format(frameMsg, f.resource, f.x, f.y, f.width, f.height, f.delay));
                }
                sw.Close();
            }
            
            
        }


    }
}